/*!
 * 定义模块 Apps (应用与功能) 中所有的功能模型。
 * 
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

/*
 * @param {Object} $    jQuery 命名空间。
 * @param {Object} $$   pittypat 命名空间。
 * @param {Object} _mod 模块 Apps (应用与功能) 的命名空间。
 * 
 * 使用 pittypat.namespace('...') 以确保 _mod 命名空间是存在的。
 * 
 * 更多说明请参见：
 * https://www.pittypat.work/com/waln/pittypat/coding/help/index.html#js。
 */
(function ($, $$, _mod) {
    'use strict';

    // 显示正在加载的消息
    $$.ui.msg = '...';

    /*
     * 为登录用户注册一个处理函数。
     * 由于没有为匿名用户注册处理函数，那么当发现用户尚未登录时，则会默认跳转到首页（登录页）。
     * 
     * 如果需要为匿名用户添加处理逻辑，应该使用如下格式的代码：
     * $$({
     *     authorized: function (_) {
     *         ...
     *     },
     *     anonymous: function (_) {
     *         // 跳转到自定义的登录页面
     *         window.location = '../../../../login.html';
     *     }
     * });
     * 
     * 如果需要自定义登录页面，则可能还需要添加 init 等处理函数。详细帮助请参见：
     * https://www.pittypat.work/com/waln/pittypat/ref/help/pittypat.js.html#pittypat。
     *
     * 参数 _ 的定义如下：
     * {
     *    user:  {Object},  // (只读)当前用户的用户信息
     *    app:   {Object},  // (只读)当前应用的命名空间，如果无法定位，则为 null
     *    mod:   {Object},  // (只读)当前模块的命名空间，如果无法定位，则为 null
     *    init:  {Boolean}, // (只读)是否正在初始化页面
     *    first: {Boolean}, // (只读)是否首次执行 authorized
     *    data:  {any}      // (读写)前述的 data 数据，或 data 函数返回的结果
     * }
     */
    $$(function (_) {
        var
            // 模块 UI 命名空间
            _ui = _mod.ui = _mod.ui || {},
            // 模块 API 命名空间
            _api = _mod.api,
            // 主工作区
            $main = $('.pt-main');

        if (_.init) {
            // 与 App (应用) 相关的操作
            {
                // 检查指定的图片是否加载成功
                function imgOk(img) {
                    if (!img.complete) {
                        return false;
                    }

                    if (typeof img.naturalWidth != "undefined" && img.naturalWidth == 0) {
                        return false;
                    }

                    return true;
                }

                /*
                 * App 结构如下：
                 * {
                 * }
                 */
                _ui.app = {
                    /*
                     * App 对象对应的 DOM HTML。
                     */
                    get html() {
                        return '<article class="pt-row pt-model model-app">' +
                            '    <hr />' +
                            '    <header class="hover">' +
                            '        <div class="pt-row-icon">' +
                            '            <img class="model-app-icon big" src="../app.png" alt="" />' +
                            '        </div>' +
                            '        <div class="pt-row-info">' +
                            '            <div>' +
                            '                <span class="pt-model-prop model-app-name"></span>' +
                            '                <span class="pt-model-prop model-app-version theme-text-2"></span>' +
                            '            </div>' +
                            '            <div class="w-8 hidden-phone">' +
                            '                <span class="pt-model-prop model-app-date"></span>' +
                            '                <span class="pt-model-prop model-app-time theme-text-2"></span>' +
                            '            </div>' +
                            '            <div class="w-13 hidden-phone">' +
                            '                <span class="pt-model-prop model-app-developer"></span>' +
                            '            </div>' +
                            '        </div>' +
                            '        <div class="pt-row-more">' +
                            '            <button class="mdc-ripple-surface mdc-ripple-surface--primary" data-target-dialog="#set-position-dialog" data-mdc-ripple-is-unbounded data-mdc-auto-init="MDCRipple">' +
                            '                <i class="material-icons">low_priority</i>' +
                            '            </button>' +
                            '            <i class="material-icons">expand_more</i>' +
                            '        </div>' +
                            '    </header>' +
                            '    <section></section>' +
                            '</article>';
                    },

                    /*
                     * 将指定的 App 对象添加到指定 DOM 列表的指定位置。
                     * 
                     * @param {any}    args   _api.list 的 args 事件创建的参数。
                     * @param {Object} model  一个 App 对象。
                     * @param {Number} pos    插入位置，非数字将清空现有列表，小于 0 将添加到最后。
                     * @param {jQuery} $list  要插入的 DOM 列表。
                     */
                    insert: function (args, model, pos, $list) {
                        if (!model) {
                            // 没有提供 App 对象
                            return null;
                        }

                        if (!$list || !$list.length) {
                            // 目标元素列表
                            $list = $main.find('>article>section');
                        }

                        if (!$$.util.is.int(pos)) {
                            // 添加到列表最后
                            pos = -1;
                        }

                        // 目前位置上当前元素
                        var $next = pos >= 0 ? $list.children('.model-app').eq(pos) : null,
                            $model = null;

                        if ($next && $next.length) {
                            // 插入到目标元素之前
                            $model = $(_ui.app.html).insertBefore($next);
                        } else {
                            // 添加到列表最后
                            $model = $(_ui.app.html).appendTo($list);
                        }

                        // 将对象属性更新到目标元素
                        return _ui.app.update(args, model, $model, $list).mdcInit();
                    },

                    /*
                     * 将指定的 App 对象数组添加到指定 DOM 列表的指定位置。
                     * 
                     * @param {any}    args  _api.list 的 args 事件创建的参数。
                     * @param {Object} models 一个 App 对象的数组。
                     * @param {Number} pos   插入位置，非数字将清空现有列表，小于 0 将添加到最后。
                     * @param {jQuery} $list 要插入的 DOM 列表。
                     */
                    insertAll: function (args, models, pos, $list) {
                        if (!$list || !$list.length) {
                            // 目标元素列表
                            $list = $main.find('>article>section');
                        }

                        if (!$$.util.is.int(pos)) {
                            // 清空现有列表
                            $list.empty();
                            // 添加到列表最后
                            pos = -1;
                        }

                        if (models && models.length) {
                            if (pos <= 0) {
                                // 添加到最前或最后
                                models.each(function (model) {
                                    _ui.app.insert(args, model, pos, $list);
                                });
                            } else {
                                // 添加到指定位置
                                models.each(function (model, i) {
                                    _ui.app.insert(args, model, pos + i, $list);
                                });
                            }
                            
                            // 检查应用图标图片是否加载成功，如果不成功，则显示默认的图标
                            $list.find('img.model-app-icon').one('error', function () {
                                this.parentElement.innerHTML = '<i class="material-icons big">crop_original</i>';
                            });
                        }

                        return $list;
                    },

                    /*
                     * 将指定的 App 对象更新到现有的 DOM。
                     * 
                     * @param {any}    args  _api.list 的 args 事件创建的参数。
                     * @param {Object} model  一个 App 对象。
                     * @param {jQuery} $model 现有的 DOM。
                     * @param {jQuery} $list 隶属的 DOM 列表。
                     */
                    update: function (args, model, $model, $list) {
                        if (!$list || !$list.length) {
                            // 目标元素列表
                            $list = $main.find('>article>section');
                        }

                        if (!$model || !$model.length) {
                            // 没有提供 $model 时根据 model 或 args 查找目标元素
                            $model = $list.children('#model-app-' + model.id);
                        }

                        if (model && $model.length) {
                            var $h = $model
                                .attr('id', 'model-app-' + model.id)
                                .data('model', model)
                                .children('header');

                            $h.find('.model-app-icon').attr('src', $$.web.url('~/com/' + model.developerCode.toLowerCase() + '/' + model.identifier.toLowerCase() + '/app.png'));
                            $h.find('.model-app-name').text(model.name);
                            $h.find('.model-app-version').text(model.version);
                            $h.find('.model-app-date').text($$.util.fmt.day(model.installTime));
                            $h.find('.model-app-time').text($$.util.fmt.timeMinute(model.installTime));
                            $h.find('.model-app-developer').text(model.developerName);
                        }

                        return $model;
                    },

                    /*
                     * 将指定的 App 对象对应的 DOM 元素从列表中移除。
                     * 
                     * @param {any}    args  _api.list 的 args 事件创建的参数。
                     * @param {Object} model  一个 App 对象。
                     * @param {jQuery} $list 要从中移除元素的 DOM 列表。
                     */
                    remove: function (args, model, $list) {
                    }
                };

                // 为 _api.list 注册事件，_api.list 定义在 _api.js 中
                _api.list
                    // 当应用列表请求成功时触发的事件
                    .on('success', function (e) {
                        // e.args 为执行请求的参数
                        // e.result 为请求结果，其定义参见 _api.js 中 _api.list 中的输出部分

                        // 对列表进行排序
                        $$.util.array.sort(e.result, function (x, y) {
                            return x.position - y.position;
                        });

                        // 将列表添加到页面
                        _ui.app.insertAll(e.args, e.result);
                    })

                    // 当应用列表加载成功时触发的事件
                    .on('load', function (e) {
                        // 隐藏正在加载的消息
                        $$.ui.msg = '';
                    });

                // 将 App 相关的事件委托给 $main
                $main
                    // 为应用加载模块列表
                    .on('children', '.model-app', function (evt) {
                        $$.ui.msg = '...';
                        _api.modules
                            // 传递应用的 id
                            .one('args', function (e) {
                                e.args = evt.model.id;
                            })
                            .one('load', function () {
                                evt.childrenLoaded = true;
                                $$.ui.msg = '';
                            })();
                    });

                // 设置位置对话框
                $('#set-position-dialog')
                    // 对话框即将打开
                    .on('opening', function (event) {
                        var $list = $('#set-position-position').empty(),
                            app = event.model,
                            $apps = $('.model-app'),
                            n = $apps.length;

                        n = n < 10 ? 1 : (n < 100 ? 2 : (n < 1000 ? 3 : 4));

                        $apps.each(function (i) {
                            var m = $(this).data('model'),
                                $o = $('<option value="' + m.position + '"></option>'),
                                si = (i + 1).toString().padLeft('0', n);

                            if (m.position < app.position) {
                                $o.text(si + ': ' + m.name + ' 之前');
                            } else if (m.position > app.position) {
                                $o.text(si + ': ' + m.name + ' 之后');
                            }

                            if (m == app) {
                                $o.text(si + ': ' + '当前位置').prop('selected', true);
                            }

                            $list.append($o);
                        });

                        $('#set-position-name').text(app.name);
                    })

                    // 用户点击了确定按钮
                    .on('ok', function (event) {
                        var app = event.model;
                        $$.ui.msg = '...';
                        _api.setPosition
                            // 获取参数
                            .one('args', function (e) {
                                e.args = {
                                    id: event.model.id,
                                    position: $$.util.int.parse($('#set-position-position').val())
                                };
                            })

                            // 如果前后位置没有发生变化，则不需要提交
                            .one('before', function (e) {
                                e.cancel = e.args.position == app.position;
                            })

                            // 当设置成功后关闭对话框，刷新导航和当前列表
                            .one('success', function (e) {
                                // 刷新当前列表
                                _api.list();

                                // 刷新导航列表
                                $('.pt-nav-refresh').trigger('click');
                            })

                            .one('load', function () {
                                $$.ui.msg = '';
                                // 关闭对话框
                                event.done = true;
                            })();
                    });
            }

            // 与 Module (模块) 相关的操作
            {
                /*
                 * Module 结构如下：
                 * {
                 * }
                 */
                _ui.module = {
                    /*
                     * Module 对象对应的 DOM HTML。
                     */
                    get html() {
                        return '<article class="pt-row pt-model model-module">' +
                            '    <hr />' +
                            '    <header>' +
                            '        <div class="pt-row-icon">' +
                            '            <i class="material-icons">bubble_chart</i>' +
                            '        </div>' +
                            '        <div class="pt-row-info">' +
                            '            <div class="w-15">' +
                            '                <span class="pt-model-prop model-module-name"></span>' +
                            '            </div>' +
                            '            <div>' +
                            '                <p class="pt-model-prop model-module-description theme-text-2"></p>' +
                            '            </div>' +
                            '        </div>' +
                            '        <div class="pt-row-more">' +
                            '            <i></i>' +
                            '            <i></i>' +
                            '        </div>' +
                            '    </header>' +
                            '</article>';
                    },

                    /*
                     * 将指定的 Module 对象添加到指定 DOM 列表的指定位置。
                     * 
                     * @param {any}    args  _api.list 的 args 事件创建的参数。
                     * @param {Object} model  一个 Module 对象。
                     * @param {Number} pos   插入位置，非数字将清空现有列表，小于 0 将添加到最后。
                     * @param {jQuery} $list 要插入的 DOM 列表。
                     */
                    insert: function (args, model, pos, $list) {
                        if (!model) {
                            // 没有提供 App 对象
                            return null;
                        }

                        if (!$list || !$list.length) {
                            // 目标元素列表
                            $list = $main.find('#model-app-' + args + '>section');
                        }

                        if (!$$.util.is.int(pos)) {
                            // 添加到列表最后
                            pos = -1;
                        }

                        // 目前位置上当前元素
                        var $next = pos >= 0 ? $list.children('.model-module').eq(pos) : null,
                            $model = null;

                        if ($next && $next.length) {
                            // 插入到目标元素之前
                            $model = $(_ui.module.html).insertBefore($next);
                        } else {
                            // 添加到列表最后
                            $model = $(_ui.module.html).appendTo($list);
                        }

                        // 将对象属性更新到目标元素
                        return _ui.module.update(args, model, $model, $list);
                    },

                    /*
                     * 将指定的 Module 对象数组添加到指定 DOM 列表的指定位置。
                     * 
                     * @param {any}    args  _api.list 的 args 事件创建的参数。
                     * @param {Object} models 一个 Module 对象的数组。
                     * @param {Number} pos   插入位置，非数字将清空现有列表，小于 0 将添加到最后。
                     * @param {jQuery} $list 要插入的 DOM 列表。
                     */
                    insertAll: function (args, models, pos, $list) {
                        if (!$list || !$list.length) {
                            // 目标元素列表
                            $list = $main.find('#model-app-' + args + '>section');
                        }

                        if (!$$.util.is.int(pos)) {
                            // 清空现有列表
                            $list.empty();
                            // 添加到列表最后
                            pos = -1;
                        }

                        if (models && models.length) {
                            if (pos <= 0) {
                                // 添加到最前或最后
                                models.each(function (model) {
                                    _ui.module.insert(args, model, pos, $list);
                                });
                            } else {
                                // 添加到指定位置
                                models.each(function (model, i) {
                                    _ui.module.insert(args, model, pos + i, $list);
                                });
                            }
                        }

                        return $list;
                    },

                    /*
                     * 将指定的 Module 对象更新到现有的 DOM。
                     * 
                     * @param {any}    args  _api.list 的 args 事件创建的参数。
                     * @param {Object} model  一个 Module 对象。
                     * @param {jQuery} $model 现有的 DOM。
                     * @param {jQuery} $list 隶属的 DOM 列表。
                     */
                    update: function (args, model, $model, $list) {
                        if (!$list || !$list.length) {
                            // 目标元素列表
                            $list = $main.find('#model-app-' + args + '>section');
                        }

                        if (!$model || !$model.length) {
                            // 没有提供 $model 时根据 model 或 args 查找目标元素
                            $model = $list.children('#model-model-' + model.id);
                        }

                        if (model && $model.length) {
                            var $h = $model
                                .attr('id', 'model-module-' + model.id)
                                .data('model', model)
                                .children('header');

                            $h.find('.model-module-name').text(model.name);
                            $h.find('.model-module-description').text(model.description);
                        }

                        return $model;
                    }
                };

                // 为 _api.list 注册事件，_api.list 定义在 _api.js 中
                _api.modules
                    // 当应用列表请求成功时触发的事件
                    .on('success', function (e) {
                        // 对列表进行排序
                        $$.util.array.sort(e.result, function (x, y) {
                            return x.position - y.position;
                        });

                        // 将列表添加到页面
                        _ui.module.insertAll(e.args, e.result);
                    });
            }

            // 初始化 mdc
            $main.mdcInit();
        }

        // 模块入口：
        // 加载应用列表
        _api.list();
    });
})(jQuery, pittypat, pittypat.namespace('waln.authority.apps'));